在前幾天,我們已經建立了專案目錄與 pyproject.toml,甚至用 Hatch 建立好了虛擬環境。
那麼接下來就要面對另一個老問題:套件要怎麼安裝,版本要怎麼控管?
這不是 Python 獨有的困擾,所有語言都有同樣的痛點。因為套件會不斷更新,API 可能變動,甚至可能帶來新的 bug。如果缺乏策略,今天能跑的程式,明天就可能壞掉。
最直覺的方法是直接安裝:
pip install requests
這會安裝當下最新的版本。
👉 適合個人實驗、一次性腳本,或版本要求不嚴格的小專案。
另一種方式是明確指定版本,在 pyproject.toml 中寫死:
[project]
dependencies = [
  "requests==2.31.0",
  "pydantic>=2.5,<2.6"
]
👉 適合團隊合作或需要長期維護的專案。
Python 的 PEP 440 提供了多種版本約束語法,Hatch 也完全支援:
[project]
name = "awesome-app"
requires-python = ">=3.11,<3.13"
dependencies = [
  "requests>=2.32,<3",    # 區間鎖定(常見做法)
  "python-dateutil==2.8.*",  # 只允許 patch 升級
  "numpy~=1.26",          # 相容版號,允許 minor 內更新
]
>=2.32,<3):可控範圍內升級。==2.8.*):僅允許 patch 變動。~=1.26):允許小版本更新,但不跳大版本。👉 工程實務上,通常會依專案穩定性需求,混搭這些策略。
實務上,我們會把依賴分成兩類:
[project].dependencies
extra-dependenciesHatch 允許你在環境下直接指定額外套件:
[tool.hatch.envs.dev]
extra-dependencies = [
  "pytest>=8.3,<9",
  "ruff==0.6.*",
  "mypy~=1.11"
]
這樣當你執行:
hatch env create dev
Hatch 就會建立一個名為 dev 的環境,並安裝這些工具。
👉 適合快速建立專用環境,但這些依賴只存在於 Hatch 的設定裡,外部工具(例如 pip、Poetry)無法重用。
optional-dependencies若你希望這些依賴能在 不同工具中共享,應該把它們放在 pyproject.toml 的 [project.optional-dependencies]:
[project.optional-dependencies]
dev = ["pytest>=8.3,<9", "ruff==0.6.*", "mypy~=1.11"]
docs = ["mkdocs", "mkdocs-material"]
這樣除了 Hatch,其他工具也能用:
pip install '.[dev]'
pip install '.[docs]'
features接著,你可以在 Hatch 的環境設定裡引用這些 extras:
[tool.hatch.envs.dev]
features = ["dev"]
[tool.hatch.envs.docs]
features = ["docs"]
hatch env create dev → 會自動安裝 pytest、ruff、mypy。hatch env create docs → 會自動安裝 mkdocs、mkdocs-material。👉 差別在於重用性:
extra-dependencies → 只能在 Hatch 裡用。features → 直接連結到 extras([project.optional-dependencies]),能跨工具重用。| 寫法 | 範例 | 適合情境 | 
|---|---|---|
extra-dependencies | 
[tool.hatch.envs.dev].extra-dependencies = ["pytest"] | 
只想在 Hatch 中加特定套件,不需要跨工具支援 | 
optional-dependencies + features | 
[project.optional-dependencies].dev = [...]  [tool.hatch.envs.dev].features = ["dev"] | 
希望依賴群組可被 pip/Poetry/Hatch 等工具重用,是工程化最佳實務 | 
[project]
name = "awesome-app"
requires-python = ">=3.11,<3.13"
dependencies = [
  "requests>=2.32,<3",
  "numpy~=1.26",
]
[project.optional-dependencies]
dev = ["pytest>=8.3,<9", "ruff==0.6.*", "mypy~=1.11"]
docs = ["mkdocs", "mkdocs-material"]
[tool.hatch.envs.dev]
features = ["dev"]
[tool.hatch.envs.docs]
features = ["docs"]
[tool.hatch.envs.experiment]
extra-dependencies = ["rich", "httpx"]
dev → 引用 extras → 跨工具都能用docs → 同上experiment → 只在 Hatch 裡多裝 rich 和 httpx,不對外公開在上述的設定完成後,你可以使用這個指令
hatch env show
他就可以在你的專案,顯示出相關的環境設定

身為 Java 開發者,我習慣透過切換不同的 JDK 版本來因應需求,但在 Python 世界,虛擬環境能做到更高層次的隔離與依賴管理。雖然各有優缺點,但這種便利性確實讓我對 Python 工程化有新的體驗。
而在本章的重點就是,依賴管理的本質,就是在 「快」 和 「穩」 之間取捨:
extra-dependencies,直接在環境加需要的套件。optional-dependencies + features,抽象成 extras,確保跨工具一致性。明天我們將進入 Day 7 - 可重現環境策略:constraints / lock 與快取,來進一步探討如何讓環境真正可重現。這就有點像 TypeScript/Node.js 專案中的 package-lock.json 或 yarn.lock,究竟 Python 世界的解法是什麼呢?我們接著看下去。